#include <stdlib.h>
#include <vmath.h>
#include "material.h"
#include "sdr.h"

struct material {
	char *name;
	char *sdrname;

	struct shader *sdr;

	struct mattr *attr_list;
};

struct material *mat_create(void)
{
	struct material *m;

	if(!(m = malloc(sizeof *m))) {
		return 0;
	}
	memset(m, 0, sizeof *m);
	return m;
}

void mat_free(struct material *m)
{
	while(m->attr_list) {
		struct mattr *ma = m->attr_list;
		m->attr_list = ma->next;

		free(ma->name);
		free(ma->texname);
		free(ma);
	}
	free(m->name);
}

static int replace_string(char **dst, const char *src)
{
	char *tmp;

	if(!(tmp = malloc(strlen(src) + 1))) {
		return -1;
	}
	strcpy(tmp, src);
	free(*dst);
	*dst = tmp;
	return 0;
}

int mat_set_name(struct material *m, const char *name)
{
	return replace_string(&m->name, name);
}

const char *mat_get_name(struct material *m)
{
	return m->name;
}

int mat_set_shader(struct material *m, const char *sdrname)
{
	if(replace_string(&m->sdrname, sdrname) == -1) {
		return -1;
	}

	if(!(m->sdr = sdr_create())) {
		return -1;
	}
	if(sdr_load(m->sdr, sdrname) == -1) {
		sdr_free(m->sdr);
		m->sdr = 0;
		return -1;
	}

	return 0;
}

const char *mat_get_shader_name(struct material *m)
{
	return m->sdrname;
}

struct shader *mat_get_shader(struct material *m)
{
	return m->sdr;
}

int mat_add_attr(struct material *m, struct mattr *attr)
{
	attr->next = m->attr_list;
	m->attr_list = attr;
	return 0;
}

struct mattr *mat_get_attr(struct material *m, const char *attr_name)
{
	struct mattr *ma = m->attr_list;

	while(ma) {
		if(strcmp(ma->name, attr_name) == 0) {
			return ma;
		}
		ma = ma->next;
	}
	return 0;
}


vec4_t mat_attr_value(struct material *m, const char *attr_name, vec2_t tc, vec4_t def)
{
	vec4_t res;
	struct mattr *ma = mat_get_attr(m, attr_name);
	if(!ma) {
		return def;
	}

	res = ma->val;

	if(ma->tex) {
		vec4_t tc4 = v4_transform(v4_cons(tc.x, tc.y, 0, 1), ma->texmat);

		vec4_t texel = tex_lookup(ma->tex, tc4);
		res = v4_mul(res, texel);
	}

	return res;
}


int mattr_set_name(struct mattr *ma, const char *name)
{
	return replace_string(&ma->name, name);
}

int mattr_set_texture(struct mattr *ma, const char *tex)
{
	if(replace_string(&ma->texname, tex) == -1) {
		return -1;
	}
	ma->tex = 0;	/* invalidate cached texture pointer */
	return 0;
}
